<?php
declare(strict_types=1);

namespace app\shop\logic;

use app\shop\enums\coupon\CouponStatus;
use app\shop\enums\order\OrderStatus;
use app\shop\enums\order\refund\RefundStatus;
use app\shop\enums\user\UserMoneyChangeType;
use app\shop\enums\user\UserMoneyTransactionType;
use app\shop\exception\FailException;
use app\shop\exception\ParamsErrorException;
use app\shop\model\coupon\CouponCenterModel;
use app\shop\model\order\OrderModel;
use app\shop\model\order\OrderRefundModel;
use app\shop\model\user\UserCouponModel;
use app\shop\model\user\UserFavoriteModel;
use app\shop\model\user\UserModel;
use app\shop\model\user\UserMoneyLogModel;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use think\helper\Arr;
use think\Paginator;

/**
 * @property UserModel $model
 */
class UserLogic extends BaseLogic
{
    public function __construct()
    {
        $this->model = new UserModel();
    }

    /**
     * 仪表板信息
     * @param array $params
     * @return array
     * @throws DbException
     */
    public function dashboard(array $params): array
    {
        $user = UserModel::where('id', $params['user_id'])->findOrEmpty();
        if ($user->isEmpty()) {
            return [
                'rights'    => [
                    'balance'      => 0,
                    'coupon_num'   => 0,
                    'favorite_num' => 0,
                ],
                'order_bar' => $this->orderBar($params),
                'coupon'    => [
                    'eligibility' => true,
                ],
            ];
        }

        $couponNum    = UserCouponModel::where([
            ['user_id', '=', $user->id],
            ['status', '=', CouponStatus::TO_USE]
        ])->count();
        $favoriteNumb = UserFavoriteModel::where([
            ['user_id', '=', $user->id]
        ])->count();
        $card = [];
        if($user->grade_id > 0){
            $card['grade_name'] = Db::name('distribution_grade')->where('id', $user->grade_id)->value('name');
            if(isset($user->terminate_time)){
                $card['terminate_time'] = date('Y-m-d H:i:s', $user->terminate_time);
            }
        }
        return [
            'rights'    => [
                'balance'      => $user->money,
                'coupon_num'   => $couponNum,
                'favorite_num' => $favoriteNumb,
            ],
            'order_bar' => $this->orderBar($params),
            'coupon'    => [
                'eligibility' => $this->isEligibleForCoupon(),
            ],
            'card'      => $card,
        ];
    }

    /**
     * 订单数据栏
     * @param array $params
     * @return array
     * @throws DbException
     */
    private function orderBar(array $params): array
    {
        $data = OrderStatus::getData();
        $data = array_filter($data, function ($item) {
            return in_array($item['value'], [
                OrderStatus::TO_PAT,
                OrderStatus::TO_SHIPPED,
                OrderStatus::TO_RECEIVED,
                OrderStatus::TO_EVALUATE,
            ]);
        });

        $counts       = OrderModel::where('user_id', $params['user_id'])
            ->whereIn('status', array_column($data, 'value'))
            ->group('status')
            ->column('count(*) as count', 'status');
        $refundCounts = OrderRefundModel::where(['user_id' => $params['user_id'], 'status' => RefundStatus::WAIT_AUDIT])->count() ?? 0;

        $data = [
            'to_pay'      => $counts[OrderStatus::TO_PAT] ?? 0,
            'to_ship'     => $counts[OrderStatus::TO_SHIPPED] ?? 0,
            'to_receive'  => $counts[OrderStatus::TO_RECEIVED] ?? 0,
            'to_evaluate' => $counts[OrderStatus::TO_EVALUATE] ?? 0,
            'refund'      => $refundCounts,
        ];

        return array_merge($data);
    }

    /**
     * 编辑用户信息
     * @param array $params
     * @return array
     * @throws FailException
     * @throws ParamsErrorException
     */
    public function edit(array $params): array
    {
        $user = $this->model->where('id', $params['user_id'])->findOrEmpty();
        if ($user->isEmpty()) {
            throw new ParamsErrorException('用户信息异常，请稍后再试');
        }
        if (Arr::has($params, 'username')) {
            $username = $this->model->where('id', '<>', $user->id)->where('username', $params['username'])->value('username');
            if ($username) {
                throw new ParamsErrorException('用户名已被使用，请更换');
            }
        }
        if (Arr::has($params, 'nickname')) {
            $nickname = $this->model->where('id', '<>', $user->id)->where('nickname', $params['nickname'])->value('nickname');
            if ($nickname) {
                throw new ParamsErrorException('昵称已被使用，请更换');
            }
        }
        try {
            $user = UserModel::update($params, ['id' => $params['user_id']]);
        } catch (Exception $e) {
            throw new FailException('修改失败', null, $e);
        }

        return $user->toArray();
    }

    /**
     * 余额日志列表
     * @param array $params
     * @return array|Paginator
     */
    public function balanceLog(array $params): Paginator|array
    {
        $query = UserMoneyLogModel::getQuery();

        switch ($params['type']) {
            case UserMoneyTransactionType::INCOME:
                $query->where('money', '>', 0);
                break;
            case UserMoneyTransactionType::EXPEND:
                $query->where('money', '<', 0);
                break;
            default:
                break;
        }

        $this->buildEqualQuery($query, $params, [
            'user_id' => 'user_id',
        ]);

        $query->order('id', 'desc');

        $result = UserMoneyLogModel::paginateListQuery($query, true);

        // 交易类型
        $result['tabs'] = UserMoneyTransactionType::getData();
        //变更类型
        $result['types'] = UserMoneyChangeType::getData();

        //统计
        $balance       = UserModel::where('id', $params['user_id'])->field(['money'])->findOrEmpty()['money'] ?? '0.00';
        $totalRecharge = UserMoneyLogModel::where('user_id', $params['user_id'])->where('type', UserMoneyChangeType::RECHARGE)->sum('money');
        $totalExpend   = UserMoneyLogModel::where('user_id', $params['user_id'])->where('money', '<', 0)->sum('money');
        $totalExpend   = abs($totalExpend);

        //数据表单位为分，转换为元
        $result['statistics'] = [
            'balance'        => $balance,
            'total_recharge' => bcdiv((string)$totalRecharge, '100', 2),
            'total_expend'   => bcdiv((string)$totalExpend, '100', 2),
        ];

        return $result;
    }

    /**
     * 领券中心是否展示 New 状态
     * @return bool
     * @throws DbException
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function isEligibleForCoupon(): bool
    {
        $currentTimestamp = time();

        $coupons = CouponCenterModel::where('remain_num', '>', 0)
            ->with(['user_coupon'])
            ->where(function ($query) use ($currentTimestamp) {
                $query->whereTime('start_time', '<=', $currentTimestamp)
                    ->whereTime('end_time', '>=', $currentTimestamp);
            })
            ->where(function ($query) use ($currentTimestamp) {
                $query->whereTime('active_start_time', '<=', $currentTimestamp)
                    ->whereTime('active_end_time', '>=', $currentTimestamp);
            })
            ->append(['disabled'])
            ->select();
        if ($coupons->isEmpty()) {
            return false;
        }


        foreach ($coupons as $coupon) {
            if (!$coupon->disabled) {
                return true;
            }
        }

        return false;
    }
}
